﻿using LitJson;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public delegate void Callback();
public delegate void CallbackShip(Ship ship);
public delegate void CallbackWeapon(Weapon weapon);
public delegate void CallbackShipUI(ShipUI ship);
public delegate void CallbackPart(Part part);
public delegate void CallbackGameObject(GameObject gameObject);
public delegate void CallbackShipEventBehaviour(ShipEventBehaviours behaviour);
public delegate void CallbackPartBlock(PartBlock block);


public delegate void CallbackInt(int num);
public delegate void CallbackIntInt(int num1, int num2);
public delegate void CallbackFloat(float num);
public delegate void CallbackString(string value);
public delegate void CallbackVector3(Vector3 value);
public delegate void CallbackCollision2D(Collision2D value);
public delegate void CallbackCollider2D(Collider2D value);
public delegate void CallbackUri(Uri value);
public class CommonData
{
    public enum DataType
    {
        NONE,
        Int,
        Float,
        Bool,
        String,
    }
    public DataType m_DataType;
    public int m_TargetDataInt;
    public float m_TargetDataFloat;
    public bool m_TargetDataBool;
    public string m_TargetDataString;
}
class Utils
{
    public enum Align
    {
        ALIGN_LEFT_TOP,
        ALIGN_RIGHT_TOP,
        ALIGN_LEFT_BOTTOM,
        ALIGN_RIGHT_BOTTOM,
        ALIGN_CENTER,
    }
    public const int _PARTS_RENDER_ORDER_ = 1;
    public const string _SHIP_UI_PATH_ = "Prefabs/UI/ShipDesigner/UI/ShipUI/";
    public const string _ENGINE_EFFECT_PATH_ = "Effects/Engine/";
    public const string _EXPLOTION_EFFECT_PATH_ = "Effects/Explotion/";

    public static bool IsAndroid()
    {
#if UNITY_ANDROID
        return true;
#endif
        return false;
    }
    public static string GetDataPath()
    {
        string configPath = "./GameData/";
#if UNITY_ANDROID
        ConfigPath = Application.persistentDataPath + "/GameData/";
#endif
        return configPath;
    }

    static public Sprite LoadSpriteByResouce(string url)
    {
        Sprite sprite = Resources.Load<Sprite>(url);
        if (sprite)
            return GameObject.Instantiate(sprite);
        return null;
    } 

    /// <summary>
    /// 以IO方式进行加载
    /// </summary>
    static public Sprite LoadSpriteByIo(string url, Vector2 piovt, float pixelPerUnit = 100)
    {
        if(!File.Exists(url))
        {  
            return null;
        }
        //创建文件读取流
        using (FileStream fileStream = new FileStream(url, FileMode.Open, FileAccess.Read))
        {
            //创建文件长度缓冲区
            byte[] bytes = new byte[fileStream.Length];
            //读取文件
            fileStream.Read(bytes, 0, (int)fileStream.Length);

            //释放文件读取流
            fileStream.Close();
            //释放本机屏幕资源
            fileStream.Dispose();

            //创建Texture
            int width = 256;
            int height = 256;
            Texture2D texture = new Texture2D(width, height);
            texture.LoadImage(bytes);
            //ImageConversion.LoadImage(texture, bytes);
            //创建Sprite
            Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), piovt, pixelPerUnit);
            return sprite;
        }
    }


    static public bool IsOnUI(Vector3 pos)
    {
        var canvas = GetCanvas();
        if (canvas == null)
            return false;
        GraphicRaycaster caster = canvas.GetComponent<GraphicRaycaster>();
        if (caster == null)
            return false;

        PointerEventData pData = new PointerEventData(EventSystem.current);

        pData.position = pos;
        pData.delta = Vector2.zero;
        pData.scrollDelta = Vector2.zero;

        List<UnityEngine.EventSystems.RaycastResult> canvasHits = new List<UnityEngine.EventSystems.RaycastResult>();
        caster.Raycast(pData, canvasHits);


        return canvasHits.Count > 0;
    }
    public static Canvas GetCanvas()
    {

        var foundCanvas = GameObject.FindGameObjectsWithTag("Canvas");
        foreach (var canvas in foundCanvas)
        {
            if (canvas.activeSelf && canvas.GetComponent<Canvas>())
                return canvas.GetComponent<Canvas>();
        }
        return null;
    }
    public static GameObject GetUserUI()
    {
        var userUI = GameObject.FindGameObjectWithTag("UserUI");
        return userUI;
    }
    public static GameObject FindObjectWithTag(string tag)
    {

        foreach (GameObject go in Resources.FindObjectsOfTypeAll(typeof(GameObject)))
        {
            if (!EditorUtility.IsPersistent(go.transform.root.gameObject) && !(go.hideFlags == HideFlags.NotEditable || go.hideFlags == HideFlags.HideAndDontSave))
            {
                if (go.tag == tag)
                    return go;
            }
        }
        return null;
    }
    public static float GetCanvasScale()
    {
        float scale = 1;
        var canvas = GetCanvas();
        if (canvas)
            scale = canvas.scaleFactor;
        return scale;
    }
    public static T DeepCopy<T>(T obj)
    {
        object retval;
        using (MemoryStream ms = new MemoryStream())
        {
            BinaryFormatter bf = new BinaryFormatter();
            //序列化成流
            bf.Serialize(ms, obj);
            ms.Seek(0, SeekOrigin.Begin);
            //反序列化成对象
            retval = bf.Deserialize(ms);
            ms.Close();
        }
        return (T)retval;
    }
    public static bool CheckReferenceIsNull<T>(T value)
    {
        if (value == null)
        {
            Debug.LogError(value.ToString() + "we cann't found the reference! at the line:" + Utils.GetLineNum());
            return true;
        }
        return false;
    }
    public static int GetLineNum()
    {
        System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace(1, true);
        return st.GetFrame(0).GetFileLineNumber();
    }
    public static bool SaveImage(Texture2D texture, string dataPath)
    {
        var dataBytes = texture.EncodeToPNG();
        FileStream fs = File.Open(dataPath, FileMode.OpenOrCreate);
        if (fs == null)
            return false;
        fs.Write(dataBytes, 0, dataBytes.Length);
        fs.Flush();
        fs.Close();
        return true;

    }

    /// <summary>
    /// 假定原点在右下角
    /// </summary>
    /// <param name="size"></param>
    /// <returns></returns>
    static public Vector3 GetPositionInScreen(Vector3 position, Vector2 size, Align align = Align.ALIGN_RIGHT_BOTTOM)
    {
        Vector3 mousePos = position + new Vector3(-10, -10);
        float scale = 1;
        var canvas = GetCanvas();
        if (null != canvas)
            scale = canvas.scaleFactor;
        size *= scale;

        switch (align)
        {
            case Align.ALIGN_LEFT_TOP:
                mousePos.x = Mathf.Clamp(mousePos.x, 0, Screen.width - size.x);
                mousePos.y = Mathf.Clamp(mousePos.y, size.y, Screen.height);
                break;
            case Align.ALIGN_RIGHT_TOP:
                mousePos.x = Mathf.Clamp(mousePos.x, size.x, Screen.width);
                mousePos.y = Mathf.Clamp(mousePos.y, size.y, Screen.height);
                break;
            case Align.ALIGN_LEFT_BOTTOM:
                mousePos.x = Mathf.Clamp(mousePos.x, 0, Screen.width - size.x);
                mousePos.y = Mathf.Clamp(mousePos.y, 0, Screen.height - size.y);
                break;
            case Align.ALIGN_RIGHT_BOTTOM:
                mousePos.x = Mathf.Clamp(mousePos.x, size.x, Screen.width);
                mousePos.y = Mathf.Clamp(mousePos.y, 0, Screen.height - size.y);
                break;
            case Align.ALIGN_CENTER:
                mousePos.x = Mathf.Clamp(mousePos.x, size.x / 2, Screen.width - size.x / 2);
                mousePos.y = Mathf.Clamp(mousePos.y, size.y / 2, Screen.height - size.y / 2);
                break;
        }
        return mousePos;
    }


    public static JsonData LoadJson(string path)
    {

        if (!File.Exists(path))
        {
            Debug.LogError("Utils.LoadJson() we can't found the file by path \""+path+"\"");
            return null;
        }

        string data;
        using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
        {
            FileInfo info = new System.IO.FileInfo(path);
            byte[] array = new byte[info.Length];
            fs.Read(array, 0, (int)info.Length);
            fs.Close();
            data = System.Text.Encoding.Default.GetString(array);
        }
        if (data.Length == 0)
        {
            Debug.LogError("Utils.LoadJson() seems the file of path \""+path +"\" is empty");
            return null;
        }
        JsonData jsonData = JsonMapper.ToObject(data);
        return jsonData;
    }
}
